#ifndef __COMPONENT_H
#define __COMPONENT_H
#include "stdtype.h"
#include "carray.h"
#include "dlist.h"

/* type of device and driver */
#define MX_COMPONENT_TYPE_DRV 4
#define MX_COMPONENT_TYPE_DEV 5
/* type of memory */
#define MX_COMPONENT_TYPE_MMALGOR 6
#define MX_COMPONENT_TYPE_MMSPACE 7

/* predifine for `mx_component_t` */
struct mx_component;
typedef struct mx_component mx_component_t, *mx_component_pt;

/**
 * the events of component
 */
typedef struct
{
    void (*onmount) (mx_component_pt pself);    // nullable
    void (*onumount) (mx_component_pt pself);   // nullable
    mx_bool_t (*onlinkup) (mx_component_pt pself, mx_component_pt plinker);
    void (*onlinkdown) (mx_component_pt pself, mx_component_pt plinker);    // nullable
} mx_component_events_t, *mx_component_events_pt;

/**
 * the descriptor of component
 * @note: the hash algorithm should NOT generate 0
 * @note: distinguish the types of components
 *          - linker:        lname != null && events == null
 *          - linkee:        lname == null && events != null
 *          - linker&linkee: lname != null && events != null
 */
struct mx_component
{
    /* common attributes */
    mx_uint8_t hash;                // the hash code of `name`, can't be 0
    mx_uint8_t lhash;               // the hash code of `lname`, !0 means it is a linker[&linkee] (component), or it's a linkee
    mx_uint16_t type;               // the type of component
    mx_cstring_pt name;             // the name of component
    mx_dlist_t list;                // the components chain of syatem

    /* linker's attributes */
    mx_cstring_pt lname;            // the name of the link target, it can be null
    mx_component_pt linkee;         // the linked component (linkee)

    /* linkee's attribute */
    mx_component_events_pt events;  // the events of linkee
};

/* get the type of component */
mx_uint16_t mx_component_type (mx_component_pt pcomp);
/* get the component by name */
mx_component_pt mx_component_get (mx_cstring_pt name);
/* mount the component to system */
mx_bool_t mx_component_mount (mx_component_pt pcomp, mx_cstring_pt name,
                              mx_cstring_pt lname, mx_uint16_t type, mx_component_events_pt events);
/* unmount the component from system */
void mx_component_umount (mx_component_pt pcomp);

#endif
